# 功能：对（选择题，阅读题，翻译题，作文题）实现ocr,并将其返回为正确的格式
import requests
import base64
import re
import os
import json
from openai import OpenAI
import sys


access_token = "24.9825cfb6262e262a5caa6fef4f531037.2592000.1713240501.282335-56894520"
# src = "C:\\Users\\86178\\Desktop\\shijuan2.jpg"
api_key = "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"
# 实现ocr输出 并且矫正了格式


def ocr(baidu_api, url, type):
    """
    实现对不同题型拍照
    :param baidu_api: 百度ocr_key
    :param src: 图片的路径
    :param type: ocr类型
    :return: 对应的json格式，不同题，不同json
    """
    # 先获取百度返回的接口
    access_token = baidu_api
    request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate"
    # 二进制方式打开图片文件
    f = open(url, "rb")
    img = base64.b64encode(f.read())
    params = {"image": img, "language_type": "CHN_ENG", "result_type": "big"}
    request_url = request_url + "?access_token=" + access_token
    headers = {"content-type": "application/x-www-form-urlencoded"}
    response = requests.post(request_url, data=params, headers=headers)

    # 分内容进行格式矫正
    if type == "yuedu":
        # 先计算出最大宽度 带位置的，高精度的ocr
        max_width = 0
        for words in response.json()["words_result"]:
            max_width = max(max_width, words["location"]["width"])
        article = " "
        # 在最大的50行里面的，后面只加空格，其他的都加换行符
        for words in response.json()["words_result"]:
            if words["location"]["width"] >= max_width - 50:
                # 后面只加空格
                article = article + words["words"] + " "
            else:
                article = article + words["words"] + "\n" + "  "
        return article
    if type == "xuanze":
        max_width = 0
        for words in response.json()["words_result"]:
            max_width = max(max_width, words["location"]["width"])

        choice_partten = "^[abcdABCD]\..*"  # 以A. B.等等开头的
        # 逻辑，当这个字符串的下个字符串和下一个字符串在一行，且不是以A. B. 开头的，加上括号
        # 不在一行直接换行
        article = " "
        # 在最大的50行里面的，后面只加空格，其他的都加换行符
        # 判断自己下一个是不是同一行
        now_words = response.json()["words_result"][0]
        same_row = 0
        for i, words in enumerate(response.json()["words_result"]):
            if i > 0:
                # 判断自己和前面的一个是不是同一行的
                if (
                    now_words["location"]["top"] + 10
                    > words["location"]["top"]
                    > now_words["location"]["top"] - 10
                ):
                    # 同一行
                    same_row = same_row + 1
                    # 判断下一个是不是选项开头
                    if re.match(choice_partten, words["words"]):
                        # 选项开头, 就不加括号
                        article = article + now_words["words"] + " "
                        same_row = 0
                    else:
                        # 非选项开头，加括号
                        article = article + now_words["words"] + "( )"
                else:
                    # 不是同一行，判断前面是不是有括号
                    if same_row == 0 and not re.match(
                        choice_partten, now_words["words"]
                    ):
                        # 说明前面没括号
                        article = article + now_words["words"] + "( )"
                    else:
                        article = article + now_words["words"] + " "
                now_words = words
        article = article + response.json()["words_result"][-1]["words"]
        return article
    if type == "fanyi" or type == "zuowen":
        # 先计算出最大宽度 带位置的，高精度的ocr
        max_width = 0
        for words in response.json()["words_result"]:
            max_width = max(max_width, words["location"]["width"])
        article = " "
        # 在最大的50行里面的，后面只加空格，其他的都加换行符
        for words in response.json()["words_result"]:
            if words["location"]["width"] >= max_width - 50:
                # 后面只加空格
                article = article + words["words"] + " "
            else:
                article = article + words["words"] + "\n" + "  "
        return article


def call_openai(api_key, prompt):
    """
    封装调用openai的接口
    :param api_key: openai_key
    :param prompt: 输入给gpt的提示词语
    :return: str open_ai的返回结果
    """
    client = OpenAI(
        api_key=api_key,
    )
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content.strip()


# 返回最终的结果给java
def final_ocr_res(baidu_api, openai_key, url, type):
    """
    对ocr的结果，进行修改，返回给前端,writing和translation返回正确格式的字符串,选择和阅读，则是字符串，
    :param baidu_api: 百度云key
    :param openai_key: gptkey
    :param src: 图片路径
    :param type: 题目类型
    :return:
    """
    os.environ["http_proxy"] = "http://127.0.0.1:10808"
    os.environ["https_proxy"] = "http://127.0.0.1:10808"
    ocr_res = ocr(baidu_api, url, type)
    if type == "yuedu":
        # reading_ocr_prompt = (
        #     """
        # Please generate a JSON object from the given English reading comprehension question, which includes the original text ,question and the options. The JSON should have separate fields for the original text and each option. Here's the reading comprehension question:\n\n[Insert the reading comprehension question here, including the original text and all the options.]\n\nEnsure that the original text is formatted exactly as it is in the input, and each option is separated into its own field within the JSON object. The output should be in a valid JSON format.
        # 下面是输入和输出的一个格式
        # 输入：一篇英文阅读，包括原文和选项
        # 输出：只能以json格式输出,下面这个json就是对应的输出
        # {
        #   "original_text": "This is the original text of the reading comprehension question. It should be formatted exactly as it appears in the input.",
        #   "questions": [
        #     {
        #       "question_number": 1,
        #       "question": "Why are race walkers conditioned athletes?",
        #       "options": [
        #         {"Option": This is the first option for the reading comprehension question."},
        #         {"Option": This is the second option for the reading comprehension question."},
        #         ]
        #     },
        #     {
        #       "question_number": 2,
        #       "question": "Why are race walkers conditioned athletes?",
        #       "options": [
        #         {"Option": This is the first option for the reading comprehension question."},
        #         {"Option": This is the second option for the reading comprehension question."},
        #         ]
        #     },

        #   ]
        # }
        # 要求：
        # （1）现在根据上面的提示，对下面这篇阅读题进行分割，并且返回对应的json格式。只返回json格式，不能有其他废话。
        # （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        # （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        # （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        # 英语阅读：
        # """
        #     + f"{ocr_res}"
        # )
        reading_ocr_prompt = """
        请从给定的英语阅读理解问题中生成一个JSON对象，其中包括原文、问题和选项、以及每个问题所考察的题型(例如主旨大意题、细节理解题、推理判断题、词汇理解题等等)。JSON应该为原始文本和每个选项提供单独的字段。这是阅读理解问题：确保原文的格式与输入中的格式完全相同，并且每个选项在JSON对象中都被分隔到自己的字段中。输出应采用有效的JSON格式。下面是输入和输出的一个格式
        输入：一篇英文阅读，包括原文和选项
        输出：只能以json格式输出,下面这个json就是对应的输出
        {{
        'original_text': 'This is the original text of the reading comprehension question. It should be formatted exactly as it appears in the input.',
        'questions': [
            {{
            'question_number': 1,
            'question': 'the reading comprehension question',
            'options': [  
                {{'Option': 'This is the option for the reading comprehension question.'}},  
                ] ,
            'question_type': 'The type of this question',
            }}
        ]
        }}
        要求：
        （1）现在根据上面的提示，对下面这篇阅读题进行分割，并且返回对应的json格式。只返回json格式，不能有其他废话。
        （1）现在根据上面的提示，对下面这篇阅读题进行分割，并且返回对应的json格式。只返回json格式，不能有其他废话。
        （1）现在根据上面的提示，对下面这篇阅读题进行分割，并且返回对应的json格式。只返回json格式，不能有其他废话。
        （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        （2）在original_text对应的字符串中，必须保持原来输入的阅读段落格式，不能合并成一段话，这个很重要，必须完成！！！也就是必须保证阅读正文对应的换行符位置不能改变！！！
        （3）在question_type应该是该问题所属题型，如主旨大意题、细节理解题、推理判断题、词汇理解题，句子理解题，文章结构题,作者观点题,文体风格题等等。其值必须用中文表示！
        （3）在question_type应该是该问题所属题型，如主旨大意题、细节理解题、推理判断题、词汇理解题，句子理解题，文章结构题,作者观点题,文体风格题等等。其值必须用中文表示！
        （4）在question_type应该是该问题所属题型，如主旨大意题、细节理解题、推理判断题、词汇理解题，句子理解题，文章结构题,作者观点题,文体风格题等等。其值必须用中文表示！
        (5)在json格式中的值，如果出现' " \\等可能会导致报错的符号，需要使用转义符来来将其转义，保证json格式的正确性
        (5)在json格式中的值，如果出现' " \\等可能会导致报错的符号，需要使用转义符来来将其转义，保证json格式的正确性
        (5)在json格式中的值，如果出现' " \\等可能会导致报错的符号，需要使用转义符来来将其转义，保证json格式的正确性

        输入的英语阅读如下：
            {ocr_res}"""

        result = call_openai(openai_key, reading_ocr_prompt)
        print("=========================result=========================")
        # print(ocr_res)
        # print(result)
        print("==========================================================")

        res_reading = json.loads(result)
        print(res_reading)
        return_data = {"category": "yuedu"}
        original_text = res_reading["original_text"]
        sonExe = []
        reading_type = ""
        for item in res_reading["questions"]:
            reading_exe = {}
            options = item["options"]
            size = len(options)
            reading_exe["choiceNum"] = size
            reading_exe["problem"] = item["question"]
            # print(size)
            for i in range(size):
                # print(i)
                reading_exe["choice" + str(i + 1)] = options[i]["Option"]
            sonExe.append(reading_exe)
        return_data["contenxt"] = original_text
        return_data["sonExercise"] = sonExe
        # return_data["similar_question_id"] = similar_res
        return_data["stuAnswer"] = ""
        return_data["field"] = ""
        return_data["aiComment"] = ""
        print(str(return_data))
    if type == "xuanze":
        choice_ocr_prompt_part1 = """
        现在需要你将一串包含多道英语选择题的字符串（提示：可能含有其他话，你需要将其删除）转换成易于阅读的格式，并以 JSON 的形式返回。在 JSON 中，你需要包含原问题数组，每个原问题中不仅包含原文，还要包含选项。

        首先，你需要明白字符串原本的格式可能非常混乱，每个题目之间以及每个选项之间仅有一个空格隔开，没有换行符。并且，可能会含有一些与题目无关的一些话，你也需要将其删除。因此，你的任务是将其划分成正确的格式，使其适合人们阅读，并且将其转换成 JSON 格式。

        JSON 格式的示例如下：

        {
          "questions": [
            {
              "question": "What is the capital of France?",
               "options": [  
                {"Option": This is the first option for the reading comprehension question."},  
                {"Option": This is the second option for the reading comprehension question."},  
                ]  
            },
            {
              "question": "Who wrote 'Romeo and Juliet'?",
              "options": [  
                {"Option": This is the first option for the reading comprehension question."},  
                {"Option": This is the second option for the reading comprehension question."},  
                ]  
            }
          ]
        }

        在这个示例中，`questions` 键对应一个数组，数组中每个元素都是一个对象，代表一道题目。每个题目对象中有两个键：`question` 表示题目内容，`options` 表示选项，是一个包含多个选项字符串的数组。

        因此，你需要按照这个格式将原始字符串中的题目和选项提取出来，组织成 JSON 格式返回。这样做可以使得信息更清晰易读，也更便于程序处理和解析。

        下面是输入的英语选择题字符串：
        """

        choice_ocr_prompt_part2 = """
        注意：
        只能以示例中的json格式返回，不能输出除json外任何的单词
        """
        final_prompt = choice_ocr_prompt_part1 + ocr_res + choice_ocr_prompt_part2
        res = call_openai(openai_key, final_prompt)
        res_reading = json.loads(res)
        return_data = {}
        return_data = {"category": "xuanze"}
        options = res_reading[0]["options"]
        return_data["problem"] = res_reading[0]["question"]
        for item in options:
            size = len(options)
            return_data["choiceNum"] = size
            # print(size)
            for i in range(size):
                # print(i)
                return_data["choice" + str(i + 1)] = options[i]["Option"]
        print(str(return_data))
    if type == "zuowen" or type == "fanyi":
        print(ocr_res)


if __name__ == "__main__":
    # url = sys.argv[1]
    # type = sys.argv[2]
    url = sys.argv[1]
    url = os.path.abspath(".") + "/api/target/classes/static/photo/" + url
    # type = "reading"
    # src = "1712837534932.jpg"
    # url = os.path.abspath(".") + "/api/target/classes/static/photo/" + src
    type = "zuowen"
    final_ocr_res(baidu_api=access_token, openai_key=api_key, url=url, type=type)
